package com.whfc.common.third.yuke;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.Result;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.third.yuke.result.*;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 合肥宇科 特种设备 API
 *
 * @author : qzexing
 * @version : 1.0
 * @date : 2020-07-15 10:49
 */
public class YukeApi {

    private static final Logger logger = LoggerFactory.getLogger(YukeApi.class);

    /**
     * token 过期码
     */
    public static final String TOKEN_EXPIRED_CODE = "402";

    /**
     * 时间格式化样式
     */
    private static final String TIME_PATTEN = "yyyyMMddHHmmss";

    /**
     * 获取Token url
     */
    private static final String GET_TOKEN_URL = "https://101.37.149.55/SmartSite/v2/getToken.action";

    /**
     * 获取塔机信息
     */
    private static final String GET_CRANE_INFO_URL = "http://118.31.23.115:8080/TowerCrane/v3/listDeviceInfo";

    /**
     * 获取升降机信息
     */
    private static final String GET_LIFT_INFO_URL = "http://118.31.23.115:8080/Hoist/v3/listDeviceInfo";

    /**
     * 获取塔吊实时数据
     */
    private static final String GET_CRANE_REAL_DATA_URL = "http://118.31.23.115:8080/TowerCrane/v3/listRealDeviceData";

    /**
     * 获取塔吊工作循环
     */
    private static final String GET_CRANE_RECORD_DATA_URL = "http://118.31.23.115:8080/TowerCrane/v3/listDeviceWorkingCycleByListDeviceId";

    /**
     * 获取升降机实时数据
     */
    private static final String GET_LIFT_REAL_DATA_URL = "http://118.31.23.115:8080/Hoist/v3/listDeviceDataByListDeviceId";

    /**
     * 获取升降机运行记录
     */
    private static final String GET_LIFT_RECORD_DATA_URL = "http://118.31.23.115:8080/Hoist/v3/listDeviceWorkCycleInfoByTime";

    private String username;

    private String password;

    public YukeApi(String username, String password) {
        this.username = username;
        this.password = password;
    }

    /**
     * 获取token
     *
     * @return token
     */
    public String getAccessToken() throws BizException {
        String token = "";
        Map<String, String> body = new HashMap<>();
        body.put("userName", username);
        body.put("password", password);
        try {
            String response = HttpUtil.doPost(GET_TOKEN_URL, body);
            logger.info("获取合肥宇科Token响应,response:{}", response);
            if (response != null) {
                Result result = JSON.parseObject(response, Result.class);
                if (ResultEnum.SUCCESS.getCode().equals(result.getCode()) && result.getData() != null) {
                    token = ((JSONObject) result.getData()).getString("token");
                }
            }
            return token;
        } catch (BizException b) {
            throw b;
        } catch (Exception e) {
            logger.warn("获取合肥宇科Token失败,", e);
            throw new BizException(ResultEnum.FAILURE.getCode(), ResultEnum.FAILURE.getMessage());
        }
    }

    /**
     * 获取塔吊信息
     *
     * @param deviceIds 出厂编号
     * @return 塔吊信息
     */
    public YukeResult<List<CraneInfo>> getCraneInfo(String accessToken, List<String> deviceIds) throws BizException {
        Map<String, String> body = initRequestMap(accessToken, parseDeviceList(deviceIds));
        //	要返回的字段属性 例1,1,1,0,0,0,0 从左到右分别有：基本信息 平台信息 报警设置信息 限位设置信息 传感器标定信息 注册信息和障碍物信息七种数据，1返回0不返回。
        //不填fields参数则返回所有字段属性
        body.put("fields", "1,1,1,0,0,0,0");
        //要返回的额外属性。
        // 例：1,1,1,1 从左往右分别为：
        // 项目id与项目名(部分设备可能没有此属性)
        // 在线离线状态
        // 预警告警状态
        // 在线总时长。1返回0不返回
        body.put("extraFields", "1,1,1,1");
        try {
            String response = HttpUtil.doPost(GET_CRANE_INFO_URL, body);
            logger.info("获取塔吊信息,response:{}", response);
            if (response != null) {
                Result result = JSON.parseObject(response, Result.class);
                YukeResult<List<CraneInfo>> yukeResult = new YukeResult<>();
                yukeResult.setCode(result.getCode());
                yukeResult.setMsg(result.getMsg());
                if (ResultEnum.SUCCESS.getCode().equals(result.getCode()) && result.getData() != null) {
                    //成功
                    List<CraneInfo> craneInfos = JSON.parseArray(result.getData().toString(), CraneInfo.class);
                    if (craneInfos == null || craneInfos.isEmpty()) {
                        return null;
                    }
                    yukeResult.setData(craneInfos);
                    return yukeResult;
                }
                return yukeResult;
            }
        } catch (BizException b) {
            throw b;
        } catch (Exception e) {
            logger.warn("获取塔吊信息失败,", e);
            throw new BizException(ResultEnum.FAILURE.getCode(), ResultEnum.FAILURE.getMessage());
        }
        return null;
    }


    /**
     * 获取升降机信息
     *
     * @param deviceIds 出厂编号
     * @return 塔吊信息
     */
    public YukeResult<List<LiftInfo>> getLiftInfo(String accessToken, List<String> deviceIds) throws BizException {
        Map<String, String> body = initRequestMap(accessToken, parseDeviceList(deviceIds));
        //	要返回的字段属性 例1,1,1,0,0,0,0 从左到右分别有：基本信息 平台信息 报警设置信息 限位设置信息 传感器标定信息 注册信息和障碍物信息七种数据，1返回0不返回。
        //不填fields参数则返回所有字段属性
        body.put("fields", "1,1,1,0,0,0,0");
        //要返回的额外属性。
        // 例：1,1,1,1 从左往右分别为：
        // 项目id与项目名(部分设备可能没有此属性)
        // 在线离线状态
        // 预警告警状态
        // 在线总时长。1返回0不返回
        body.put("extraFields", "1,1,1,1");
        try {
            String response = HttpUtil.doPost(GET_LIFT_INFO_URL, body);
            logger.info("获取升降机信息,response:{}", response);
            if (response != null) {
                Result result = JSON.parseObject(response, Result.class);
                YukeResult<List<LiftInfo>> yukeResult = new YukeResult<>();
                yukeResult.setCode(result.getCode());
                yukeResult.setMsg(result.getMsg());
                if (ResultEnum.SUCCESS.getCode().equals(result.getCode()) && result.getData() != null) {
                    //成功
                    List<LiftInfo> liftInfos = JSON.parseArray(result.getData().toString(), LiftInfo.class);
                    if (liftInfos == null || liftInfos.isEmpty()) {
                        return null;
                    }
                    yukeResult.setData(liftInfos);
                    return yukeResult;
                }
                return yukeResult;
            }
        } catch (BizException b) {
            throw b;
        } catch (Exception e) {
            logger.warn("获取升降机信息失败,", e);
            throw new BizException(ResultEnum.FAILURE.getCode(), ResultEnum.FAILURE.getMessage());
        }
        return null;
    }

    /**
     * 获取塔吊最新实时数据
     *
     * @param accessToken token
     * @param deviceIds   设备编码
     * @param minutes     获取指定时长的数据
     * @return 塔吊实时数据
     */
    public YukeResult<List<CraneRealData>> getCraneRealData(String accessToken, List<String> deviceIds, Integer minutes) throws BizException {
        Map<String, String> body = initRequestMap(accessToken, parseDeviceList(deviceIds));
        //获取指定时间内的数据
        body.put("history", minutes.toString());
        //筛选要查询的数据
        //screen[0]：1正常，2预警，3报警，4正常+预警，5正常+报警，6预警+报警，0查询所有
        body.put("screen", "0");
        try {
            String response = HttpUtil.doPost(YukeApi.GET_CRANE_REAL_DATA_URL, body);
            logger.info("获取塔吊实时数据,response:{}", response);
            if (response != null) {
                Result result = JSON.parseObject(response, Result.class);
                YukeResult<List<CraneRealData>> yukeResult = new YukeResult<>();
                yukeResult.setCode(result.getCode());
                yukeResult.setMsg(result.getMsg());
                if (ResultEnum.SUCCESS.getCode().equals(result.getCode()) && result.getData() != null) {
                    //成功
                    List<CraneRealData> dataList = JSONArray.parseArray(result.getData().toString(), CraneRealData.class);
                    yukeResult.setData(dataList);
                }
                return yukeResult;
            }
        } catch (BizException b) {
            throw b;
        } catch (Exception e) {
            logger.warn("获取塔吊实时数据失败,", e);
            throw new BizException(ResultEnum.FAILURE.getCode(), ResultEnum.FAILURE.getMessage());
        }
        return null;
    }


    /**
     * 获取升降机最新实时数据
     *
     * @param accessToken token
     * @param deviceIds   设备编码
     * @param minutes     获取指定时长的数据
     * @return 升降机实时数据
     */
    public YukeResult<List<LiftRealData>> getLiftRealData(String accessToken, List<String> deviceIds, Integer minutes) throws BizException {
        Map<String, String> body = initRequestMap(accessToken, parseDeviceList(deviceIds));
        //获取指定时间内的数据
        body.put("history", minutes.toString());
        //筛选要查询的数据
        //screen[0]：1正常，2预警，3报警，4正常+预警，5正常+报警，6预警+报警，0查询所有
        body.put("screen", "0");
        try {
            String response = HttpUtil.doPost(YukeApi.GET_LIFT_REAL_DATA_URL, body);
            logger.info("获取升降机实时数据,response:{}", response);
            if (response != null) {
                Result result = JSON.parseObject(response, Result.class);
                YukeResult<List<LiftRealData>> yukeResult = new YukeResult<>();
                yukeResult.setCode(result.getCode());
                yukeResult.setMsg(result.getMsg());
                if (ResultEnum.SUCCESS.getCode().equals(result.getCode()) && result.getData() != null) {
                    //成功
                    List<LiftRealData> dataList = JSONArray.parseArray(result.getData().toString(), LiftRealData.class);
                    yukeResult.setData(dataList);
                }
                return yukeResult;
            }
        } catch (BizException b) {
            throw b;
        } catch (Exception e) {
            logger.warn("获取升降机实时数据失败,", e);
            throw new BizException(ResultEnum.FAILURE.getCode(), ResultEnum.FAILURE.getMessage());
        }
        return null;
    }


    /**
     * 获取塔吊运行记录
     *
     * @param deviceIds 设备编码
     * @return 塔吊实时数据
     */
    public YukeResult<List<CraneRecordData>> getCraneRecordData(String accessToken, List<String> deviceIds, Date startTime, Date endTime) throws BizException {
        Map<String, String> body = initRequestMap(accessToken, parseDeviceList(deviceIds));
        body.put("startTime", DateUtil.formatDate(startTime, TIME_PATTEN));
        body.put("endTime", DateUtil.formatDate(endTime, TIME_PATTEN));
        try {
            String response = HttpUtil.doPost(YukeApi.GET_CRANE_RECORD_DATA_URL, body);
            logger.info("获取塔吊工作循环数据,response:{}", response);
            if (response != null) {
                Result result = JSON.parseObject(response, Result.class);
                YukeResult<List<CraneRecordData>> yukeResult = new YukeResult<>();
                yukeResult.setCode(result.getCode());
                yukeResult.setMsg(result.getMsg());
                if (ResultEnum.SUCCESS.getCode().equals(result.getCode()) && result.getData() != null) {
                    //成功
                    List<CraneRecordData> dataList = JSONArray.parseArray(result.getData().toString(), CraneRecordData.class);
                    yukeResult.setData(dataList);
                }
                return yukeResult;
            }
        } catch (BizException b) {
            throw b;
        } catch (Exception e) {
            logger.warn("获取塔吊工作循环数据失败,", e);
            throw new BizException(ResultEnum.FAILURE.getCode(), ResultEnum.FAILURE.getMessage());
        }
        return null;
    }


    /**
     * 获取升降机运行记录
     *
     * @param accessToken token
     * @param deviceIds   设备编码
     * @param startTime   开始时间
     * @param endTime     结束时间
     * @return 塔吊实时数据
     */
    public YukeResult<List<LiftRecordData>> getLiftRecordData(String accessToken, List<String> deviceIds, Date startTime, Date endTime) throws BizException {
        Map<String, String> body = initRequestMap(accessToken, parseDeviceList(deviceIds));
        body.put("startTime", DateUtil.formatDate(startTime, TIME_PATTEN));
        body.put("endTime", DateUtil.formatDate(endTime, TIME_PATTEN));
        try {
            String response = HttpUtil.doPost(YukeApi.GET_LIFT_RECORD_DATA_URL, body);
            logger.info("获取升降机运行记录数据,response:{}", response);
            if (response != null) {
                Result result = JSON.parseObject(response, Result.class);
                YukeResult<List<LiftRecordData>> yukeResult = new YukeResult<>();
                yukeResult.setCode(result.getCode());
                yukeResult.setMsg(result.getMsg());
                if (ResultEnum.SUCCESS.getCode().equals(result.getCode()) && result.getData() != null) {
                    //成功
                    List<LiftRecordData> dataList = JSONArray.parseArray(result.getData().toString(), LiftRecordData.class);
                    yukeResult.setData(dataList);
                    return yukeResult;
                }
            }
        } catch (BizException b) {
            throw b;
        } catch (Exception e) {
            logger.warn("获取升降机运行记录数据失败,", e);
            throw new BizException(ResultEnum.FAILURE.getCode(), ResultEnum.FAILURE.getMessage());
        }
        return null;
    }

    /**
     * 格式化设备列表
     *
     * @param deviceIds 设备列表
     * @return 设备列表字符串
     */
    private String parseDeviceList(List<String> deviceIds) {
        String devices = "";
        if (deviceIds == null || deviceIds.isEmpty()) {
            return devices;
        }
        StringBuilder sb = new StringBuilder();
        for (String deviceId : deviceIds) {
            sb.append(deviceId).append(",");
        }
        return sb.substring(0, sb.length() - 1);
    }

    /**
     * 构造请求Map参数
     *
     * @param deviceId 设备ID
     * @return 请求Map参数
     */
    private Map<String, String> initRequestMap(String accessToken, String deviceId) {
        Map<String, String> body = new HashMap<>();
        body.put("userName", username);
        body.put("token", accessToken);
        body.put("listDeviceId", deviceId);
        return body;
    }

}
